package com.derbysoft.dswitch.adapter.ihg.web.action.monitor;

import com.derbysoft.dswitch.adapter.ihg.common.domain.HotelMapping;
import com.derbysoft.dswitch.adapter.ihg.common.domain.HotelStatus;
import com.derbysoft.dswitch.adapter.ihg.common.repository.ChannelAuthorizationRepository;
import com.derbysoft.dswitch.adapter.ihg.common.repository.HotelRepository;
import com.derbysoft.dswitch.adapter.ihg.common.utils.DateTimeUtils;
import com.derbysoft.dswitch.adapter.ihg.common.utils.EnvironmentUtils;
import com.derbysoft.dswitch.adapter.ihg.dto.*;
import com.derbysoft.dswitch.adapter.ihg.web.utils.ApplicationContextAwareHttpServlet;
import com.derbysoft.dswitch.adapter.ihg.webservice.ProviderWebService;
import com.derbysoft.dswitch.adapter.ihg.webservice.impl.AccountProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

@Component("monitorServlet")
public class MonitorServlet extends ApplicationContextAwareHttpServlet {

    private final Log logger = LogFactory.getLog(MonitorServlet.class);

    private static final long CONNECT_DATE_BASE_TIME_OUT = 10000;
    private static final long IHG_WEBSERVICE_TIME_OUT = 10000;
    private static final String HOTEL_CODE = "GOIIN";
    private static final String VERSION = "1.003";
    private static final String REQUESTOR_ID = "14339942";

    @Autowired
    private HotelRepository hotelRepository;

    @Autowired
    @Qualifier("availProviderWebService")
    private ProviderWebService<OTAHotelAvailRQ, OTAHotelAvailRS> availProviderWebService;

    @Autowired
    private ChannelAuthorizationRepository channelAuthorizationRepository;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        boolean databaseIsAlive = false;
        boolean providerInterfaceIsAlive = false;
        try {
            databaseIsAlive = dataBaseIsAlive();
            providerInterfaceIsAlive = providerInterfaceIsAlive();

            if (databaseIsAlive && providerInterfaceIsAlive) {
                response.getWriter().print(HttpServletResponse.SC_OK);
            } else {
                response.getWriter().print(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
            logger.info("Database is alive : " + databaseIsAlive);
            logger.info("ProviderInterface is alive : " + providerInterfaceIsAlive);
        } catch (Exception e) {
            logger.error("Database is alive : " + databaseIsAlive);
            logger.error("ProviderInterface is alive : " + providerInterfaceIsAlive);
            logger.error(e.getMessage(), e);
            response.getWriter().print(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    private boolean dataBaseIsAlive() {
        return new FutureTaskCreator<HotelMapping>().create(new Callable<HotelMapping>() {
            @Override
            public HotelMapping call() throws Exception {
                return hotelRepository.loadByHotelCode(HOTEL_CODE, HotelStatus.ENABLED);
            }
        }, CONNECT_DATE_BASE_TIME_OUT) != null;
    }

    private boolean providerInterfaceIsAlive() {
        return new FutureTaskCreator<Boolean>().create(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                return availProviderWebService.invoke(createIHGRequest(),
                        AccountProvider.of(EnvironmentUtils.getGlobalIhgAvailabilityUrl(), channelAuthorizationRepository.loadAll().get(0))) != null;
            }
        }, IHG_WEBSERVICE_TIME_OUT);
    }

    private OTAHotelAvailRQ createIHGRequest() {
        OTAHotelAvailRQ otaHotelAvailRQ = new OTAHotelAvailRQ();
        otaHotelAvailRQ.setPOS(createPOS());
        otaHotelAvailRQ.setVersion(VERSION);
        otaHotelAvailRQ.setAvailRequestSegments(createAvailRequestSegments());
        return otaHotelAvailRQ;
    }

    private POS createPOS() {
        POS pos = new POS();
        Source source = new Source();
        source.setRequestorID(createRequestId());
        pos.setSource(source);
        return pos;
    }

    private RequestorId createRequestId() {
        RequestorId requestorId = new RequestorId();
        requestorId.setID(REQUESTOR_ID);
        requestorId.setType("0");
        return requestorId;
    }

    private AvailRequestSegments createAvailRequestSegments() {
        AvailRequestSegment availRequestSegment = new AvailRequestSegment();
        availRequestSegment.setAvailReqType(EnvironmentUtils.getIhgAvailabilityRequestType());
        availRequestSegment.setHotelSearchCriteria(createHotelSearchCriteria());
        availRequestSegment.setStayDateRange(createDateRange());
        availRequestSegment.setRoomStayCandidates(createRoomStay());
        availRequestSegment.setRatePlanCandidates(createRatePlanCandidates());
        AvailRequestSegments availRequestSegments = new AvailRequestSegments();
        availRequestSegments.getAvailRequestSegment().add(availRequestSegment);
        return availRequestSegments;
    }

    private RatePlanCandidates createRatePlanCandidates() {
        RatePlanCandidates ratePlanCandidates = new RatePlanCandidates();
        List<RatePlanCandidate> results = new ArrayList<RatePlanCandidate>();
        results.add(createRatePlanCandidate(channelAuthorizationRepository.loadAll().get(0).getRatePlans().get(0).getCode()));
        ratePlanCandidates.getRatePlanCandidate().addAll(results);
        return ratePlanCandidates;
    }

    private RoomStayCandidates createRoomStay() {
        RoomStayCandidates roomStayCandidates = new RoomStayCandidates();
        RoomStayCandidate roomStayCandidate = new RoomStayCandidate();
        roomStayCandidate.setNonSmoking(true);
        roomStayCandidate.setQuantity(1);
        GuestCounts guestCounts = new GuestCounts();
        guestCounts.setIsPerRoom(false);
        GuestCount guestCount = new GuestCount();
        guestCount.setCount(1);
        guestCounts.getGuestCount().add(guestCount);
        roomStayCandidate.setGuestCounts(guestCounts);
        roomStayCandidates.getRoomStayCandidate().add(roomStayCandidate);
        return roomStayCandidates;
    }

    private StayDateRange createDateRange() {
        StayDateRange stayDateRange = new StayDateRange();
        stayDateRange.setStart(DateTimeUtils.formatDate(DateTimeUtils.addDays(DateTimeUtils.today(), 3)));
        stayDateRange.setEnd(DateTimeUtils.formatDate(DateTimeUtils.addDays(DateTimeUtils.today(), 4)));
        return stayDateRange;
    }

    private HotelSearchCriteria createHotelSearchCriteria() {
        HotelSearchCriteria hotelSearchCriteria = new HotelSearchCriteria();
        Criterion criterion = new Criterion();
        HotelRef hotelRef = new HotelRef();
        hotelRef.setHotelCode(HOTEL_CODE);
        criterion.setHotelRef(hotelRef);
        hotelSearchCriteria.setCriterion(criterion);
        return hotelSearchCriteria;
    }

    private RatePlanCandidate createRatePlanCandidate(String ratePlanCode) {
        RatePlanCandidate ratePlanCandidate = new RatePlanCandidate();
        ratePlanCandidate.setRatePlanCode(ratePlanCode);
        return ratePlanCandidate;
    }
}
